﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;


namespace CalculateResistance
{
    class Program
    {
        static void Main(string[] args)
        {
            //XmlDocument doc = new XmlDocument();
            //doc.Load("去除线.xml");

            //删除孤立无用的点

            //1.构造点和线的数据
            //2.查找点上线的个数为二的点,合并这两条线     串联
            //3.查找两点之间线的个数大于二的点,合并直到两点见线为一条
            //直到只剩下连个点结束


            //LinkedList<Point> ps = new LinkedList<Point>();
            //ps.AddFirst(new Point());

            //Parallel.For(0, 10, (i) => Console.WriteLine(i));

            string path = "a.xml";
            XmlHelper x = new XmlHelper();


            Map m = new Map();
            m.StartPoint = "a";
            m.EndPoint = "f";
            Lines ls = new Lines();
            ls.Add(new Line { Id = "1", Resistance = 2, StartPoint = "a", EndPoint = "b" });
            ls.Add(new Line { Id = "2", Resistance = 2, StartPoint = "b", EndPoint = "c" });
            ls.Add(new Line { Id = "9", Resistance = 2, StartPoint = "c", EndPoint = "e" });
            ls.Add(new Line { Id = "3", Resistance = 2, StartPoint = "c", EndPoint = "d" });
            ls.Add(new Line { Id = "4", Resistance = 2, StartPoint = "d", EndPoint = "f" });
            ls.Add(new Line { Id = "5", Resistance = 2, StartPoint = "d", EndPoint = "e" });
            ls.Add(new Line { Id = "6", Resistance = 2, StartPoint = "e", EndPoint = "f" });
            ls.Add(new Line { Id = "7", Resistance = 2, StartPoint = "f", EndPoint = "g" });
            ls.Add(new Line { Id = "8", Resistance = 2, StartPoint = "g", EndPoint = "h" });
            m.Lines = ls;

            //string str = x.Serialize(ls);
            x.SaveFile(path, m);

            m = x.ParseFile<Map>(path);
            ///String.Format("{0:N}", Guid.NewGuid())
            Points ps = new Points();
            ps.AddPoint(m.Lines);
            ps.Find(p => p.Id == m.StartPoint).IsStartPoint = true;
            ps.Find(p => p.Id == m.EndPoint).IsEndPoint = true;

            DeletePointNotNeedCalculate(ps);
            Console.WriteLine();

            while (ps.Count > 2)
            {
                CalculateSeries(ps);
                CalculateMultiple(ps);
                TriangleToY(ps);
                PrintLines(ps);
                Console.WriteLine();
            }

            //Console.WriteLine("还剩下的点");
            PrintLines(ps);
            // PrintPoints(ps);
            // Console.WriteLine(x.Serialize(ps));
            Console.WriteLine("OK");
            Console.Read();
        }

        static void PrintLines(Points ps)
        {
            Lines ls = new Lines();
            XmlHelper x = new XmlHelper();

            foreach (Point p in ps)
                foreach (Line l in p.Lines)
                    if (!ls.Contains(l)) ls.Add(l);

            Console.WriteLine(x.Serialize(ls));
        }


        static void PrintPoints(Points ps)
        {
            foreach (Point p in ps)
                Console.WriteLine(p.Id);
        }

        static List<Point> GetNextPoint(Point p, Points ps)
        {
            List<string> ls = new List<string>();
            foreach (Line l in p.Lines)
            {
                ls.Add(l.StartPoint);
                ls.Add(l.EndPoint);
            }
            ls.RemoveAll(s => s == p.Id);
            //查找所有id在ls中的点
            List<Point> lp = ps.FindAll(point => ls.Any(str => str == point.Id));
            lp.Remove(p);
            return lp;
        }
        static List<Line> GetATriangle(Points ps)
        {
            List<Line> ls = new List<Line>();

            foreach (Point point1 in ps)
            {
                if (point1.Lines == null || point1.Lines.Count < 3) continue;
                //查找所有p的下一级点
                //List<Point> lps = GetNextPoint(p, ps);

                //查找下一个点
                foreach (Point point2 in GetNextPoint(point1, ps))
                {
                    if (point2.Lines == null || point2.Lines.Count < 3 || point2.Id == point1.Id) continue;
                    //查找下一个点,如果点里面有和p.id相等的,说明这个点事一个三角形的顶点
                    foreach (Point point3 in GetNextPoint(point2, ps))
                    {
                        if (point3.Lines == null || point3.Lines.Count < 3 || point3.Id == point2.Id || point3.Id == point1.Id) continue;
                        foreach (Point point4 in GetNextPoint(point3, ps))
                        {
                            if (point3.Lines == null || point3.Lines.Count < 3) continue;
                            //找到了
                            if (point1.Id == point4.Id)
                            {
                                ls.Add(point1.Lines.Find(l => l.StartPoint == point2.Id || l.EndPoint == point2.Id));
                                ls.Add(point2.Lines.Find(l => l.StartPoint == point3.Id || l.EndPoint == point3.Id));
                                ls.Add(point3.Lines.Find(l => l.StartPoint == point1.Id || l.EndPoint == point1.Id));
                                return ls;
                            }
                        }

                    }

                }
            }



            return ls;
        }
        /// <summary>
        /// 查找两条线的交点
        /// </summary>
        /// <param name="line1"></param>
        /// <param name="line2"></param>
        /// <returns></returns>
        static string GetPointOfIntersection(Line line1, Line line2)
        {
            if (line1.StartPoint == line2.StartPoint)
                return line1.StartPoint;
            if (line1.StartPoint == line2.EndPoint)
                return line1.StartPoint;

            if (line1.EndPoint == line2.StartPoint)
                return line1.EndPoint;
            if (line1.EndPoint == line2.EndPoint)
                return line1.EndPoint;

            return null;
        }
        /// <summary>
        /// 三角形转换为Y型电路
        /// </summary>
        /// <param name="ps"></param>
        static void TriangleToY(Points ps)
        {
            //判断是不是三角形电路
            List<Line> ls = GetATriangle(ps);
            if (ls.Count != 3) return;

            Point p = new Point();
            p.Id = String.Format("{0:N}", Guid.NewGuid());
            p.Lines = new List<Line>();

            ps.RemoveLines(ls);

            Line line1 = new Line { Id = String.Format("{0:N}", Guid.NewGuid()) };
            line1.Resistance = ls[0].Resistance * ls[1].Resistance / (ls[0].Resistance + ls[1].Resistance + ls[2].Resistance);
            line1.EndPoint = p.Id;
            line1.StartPoint = GetPointOfIntersection(ls[0], ls[1]);
            ps.Find(point => point.Id == line1.StartPoint).Lines.Add(line1);

            Line line2 = new Line { Id = String.Format("{0:N}", Guid.NewGuid()) };
            line2.Resistance = ls[2].Resistance * ls[1].Resistance / (ls[0].Resistance + ls[1].Resistance + ls[2].Resistance);
            line2.EndPoint = p.Id;
            line2.StartPoint = GetPointOfIntersection(ls[2], ls[1]);
            ps.Find(point => point.Id == line2.StartPoint).Lines.Add(line2);

            Line line3 = new Line { Id = String.Format("{0:N}", Guid.NewGuid()) };
            line3.Resistance = ls[2].Resistance * ls[0].Resistance / (ls[0].Resistance + ls[1].Resistance + ls[2].Resistance);
            line3.EndPoint = p.Id;
            line3.StartPoint = GetPointOfIntersection(ls[2], ls[0]);
            ps.Find(point => point.Id == line3.StartPoint).Lines.Add(line3);

            p.Lines.Add(line1);
            p.Lines.Add(line2);
            p.Lines.Add(line3);
            Console.WriteLine("发现线{0}、{1}、{2}组成三角形线路。删除这三条线", ls[0].Id, ls[1].Id, ls[2].Id);
            Console.WriteLine("新建线{0}、{1}、{2},新建点{3},把线路转换为Y型。", line1.Id, line2.Id, line3.Id, p.Id);
            ps.Add(p);
            //Console.WriteLine("生成点: " + p.Id);

        }
        static bool IsMultiple(Point p)
        {
            if (p.Lines == null || p.Lines.Count < 2) return false;
            List<string> ls = new List<string>();
            foreach (Line l in p.Lines)
            {
                ls.Add(l.StartPoint);
                ls.Add(l.EndPoint);
            }
            ls.RemoveAll(s => s == p.Id);

            foreach (string str in ls)
                if (ls.FindAll(s => { return s == str; }).Count >= 2) return true;

            return false;
        }
        /// <summary>
        /// 计算并联
        /// </summary>
        /// <param name="ps"></param>
        static void CalculateMultiple(Points ps)
        {
            Point multiplePoint = ps.Find(IsMultiple);
            while (multiplePoint != null)
            {
                //找与该点到并联的另一个点

                string pointId = "";
                List<string> ls = new List<string>();
                foreach (Line l in multiplePoint.Lines)
                {
                    ls.Add(l.StartPoint);
                    ls.Add(l.EndPoint);
                }
                ls.RemoveAll(s => s == multiplePoint.Id);

                foreach (string str in ls)
                {
                    List<string> tmp = ls.FindAll(s => { return s == str; });
                    if (tmp.Count >= 2)
                        pointId = tmp[0];
                }

                //找到发生并联的两根线
                List<Line> lines = multiplePoint.Lines.FindAll(l => l.StartPoint == pointId || l.EndPoint == pointId);
                double dR = 0;
                foreach (Line l in lines)
                    dR += 1 / l.Resistance;

                Line line = new Line();
                line.Id = String.Format("{0:N}", Guid.NewGuid());
                line.StartPoint = multiplePoint.Id;
                line.EndPoint = pointId;
                line.Resistance = 1 / dR;

                ps.RemoveLines(lines);


                ps.Find(p => p.Id == pointId).Lines.Add(line);
                multiplePoint.Lines.Add(line);

                Console.Write("在点 {0}、{1} 间发现并联，删除并联的线 ", pointId, multiplePoint.Id);
                foreach (Line l in lines)
                {
                    Console.Write(" " + l.Id);
                }
                Console.WriteLine("。 新建线 {0} 连接到点{1}、{2}，电阻为{3}", line.Id, pointId, multiplePoint.Id, line.Resistance);
                multiplePoint = ps.Find(IsMultiple);
            }
        }

        static bool IsSeries(Point p)
        {
            return !p.IsEndPoint && !p.IsStartPoint && p.Lines != null && p.Lines.Count == 2;
        }
        /// <summary>
        /// 计算串联
        /// </summary>
        /// <param name="ps"></param>
        static void CalculateSeries(Points ps)
        {
            //处理串联
            //找到点上有两根线的,并且不是起点或者终点,那么经过经过该点的两条线一定是串联的.
            //Point seriesCircuitPoint = ps.Find(p => { return !p.IsEndPoint && !p.IsStartPoint && p.Lines != null && p.Lines.Count == 2; });
            Point seriesCircuitPoint = ps.Find(IsSeries);
            while (seriesCircuitPoint != null)
            {
                Points sep = new Points();
                sep.AddPoint(seriesCircuitPoint.Lines);
                sep.Remove(seriesCircuitPoint);

                //生成新的线,用来替换该点上的两条线
                Line l = new Line();
                l.Id = String.Format("{0:N}", Guid.NewGuid());
                l.StartPoint = sep[0].Id;
                l.EndPoint = sep[1].Id;

                //计算串联电阻
                double a = Convert.ToDouble(seriesCircuitPoint.Lines[0].Resistance);
                double b = Convert.ToDouble(seriesCircuitPoint.Lines[1].Resistance);
                l.Resistance = a + b;
                Console.WriteLine("在点 " + seriesCircuitPoint.Id +
                    " 发现串联。  删除线 " + seriesCircuitPoint.Lines[0].Id + "、" + seriesCircuitPoint.Lines[1].Id +
                    "。  删除点 " + seriesCircuitPoint.Id + "。新建线 " + l.Id + " 电阻为 " + l.Resistance + " ， 连接 " +
                    l.StartPoint + "、" + l.EndPoint);
                Console.WriteLine();

                //删除之前两条线
                ps.RemoveLines(seriesCircuitPoint.Lines);
                //加上新生成的线
                ps.Find(tmp => tmp.Id == l.StartPoint).Lines.Add(l);
                ps.Find(tmp => tmp.Id == l.EndPoint).Lines.Add(l);


                ps.Remove(seriesCircuitPoint);

                seriesCircuitPoint = ps.Find(IsSeries);
            }
        }

        /// <summary>
        /// 删除不需要计算的点
        /// </summary>
        /// <param name="ps"></param>
        static void DeletePointNotNeedCalculate(Points ps)
        {
            //删除不需要计算的点
            List<Point> del = ps.FindAll(p => { return p.Lines.Count == 1 && !p.IsStartPoint && !p.IsEndPoint; });
            if (del == null || del.Count == 0)
                Console.WriteLine("没有找到不需要计算的点。");
            Console.WriteLine("删除不需要计算的点:");
            while (del != null && del.Count != 0)
            {
                foreach (Point p in del)
                    Console.Write(p.Id + "    ");
                //删除点
                ps.RemoveAll(p => { return p.Lines.Count == 1 && !p.IsStartPoint && !p.IsEndPoint; });
                //删除包含该点的线
                foreach (Point p in ps)
                    p.Lines.RemoveAll(l => { return del.Any(d => d.Id == l.StartPoint || d.Id == l.EndPoint); });

                del = ps.FindAll(p => { return p.Lines.Count == 1 && !p.IsStartPoint && !p.IsEndPoint; });
            }
            Console.WriteLine();
        }
    }
}
